use axum::body::Body;
use axum::http::{HeaderName, HeaderValue, Request};
use axum::Router;
use price_web::app::AppBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use tower::Service;

#[derive(Debug, Serialize, Deserialize)]
pub struct PriceRequest {
    pub path: String,
    pub headers: Option<HashMap<String, String>>,
    pub body: Value,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PriceResponse {
    pub status: u16,
    pub headers: HashMap<String, String>,
    pub body: Value,
}

impl PriceRequest {
    pub fn into_request(self) -> Request<Body> {
        let mut builder = Request::builder().uri(format!("/{}", self.path)).header("Content-Type", "application/json");

        // Add custom headers if they exist
        if let Some(headers) = self.headers {
            for (name, value) in headers {
                if let (Ok(name), Ok(value)) = (name.parse::<HeaderName>(), value.parse::<HeaderValue>()) {
                    builder = builder.header(name, value);
                }
            }
        }

        // 转换body为JSON字符串
        let body_str = serde_json::to_string(&self.body).unwrap_or_default();

        builder.body(Body::from(body_str)).unwrap()
    }
}

pub fn init() -> crate::Result<Api> {
    let router_map = dashmap::DashMap::new();
    let api = Api::new(router_map);
    Ok(api)
}

pub struct Api {
    router_map: dashmap::DashMap<String, Router>,
}

impl Api {
    pub fn new(router_map: dashmap::DashMap<String, Router>) -> Self {
        let app = AppBuilder::new().next_map(router_map.clone().into()).build();
        let service = app.app.clone();
        tokio::task::spawn(async move {
            app.run().await;
        });
        router_map.insert("defalut".to_string(), service);
        Self { router_map }
    }

    pub async fn req(
        &self,
        request: PriceRequest,
    ) -> PriceResponse {
        match self.router_map.get("defalut") {
            Some(router) => {
                let http_request = request.into_request();
                let res = router.value().clone().call(http_request).await.unwrap();

                let status = res.status().as_u16();

                let mut headers = HashMap::new();
                for (name, value) in res.headers() {
                    if let (Ok(name), Ok(value)) = (name.to_string().parse::<String>(), value.to_str().map(|s| s.to_string())) {
                        headers.insert(name, value);
                    }
                }

                // Get response body
                let body_bytes = axum::body::to_bytes(res.into_body(), usize::MAX).await.unwrap();
                let body = serde_json::from_slice(&body_bytes).unwrap_or(Value::Null);

                PriceResponse { status, headers, body }
            },
            None => PriceResponse { status: 404, headers: HashMap::new(), body: Value::Null },
        }
    }
}
